/**
 * @author Rid King
 * @since 2017-04-29
 * @version 1.0.0
 * @description 链条类
 */

function Chain (construct) {
    this._result = null // 结果
    this._status = Chain.STATUS.PENDING // 初始状态
    this._promiseList = [] // 回调数组

    // 初始化执行
    setTimeout((function () {
        typeof construct === 'function' && construct(this.resolve.bind(this), this.reject.bind(this))
    }).bind(this), 20)
}

// 原型链
Chain.prototype = {
    /**
     * @description 添加回调
     * @param resolve <Function> // 成功回调
     * @param reject <Function> // 失败回调
     * @return <Chain>
    */
	then: function (resolve, reject) {
        // 添加成功回调
        typeof resolve === 'function' && this._promiseList.push({
            type: Chain.TYPES.RESOLVE,
            caller: resolve
        })

        // 添加失败回调
        typeof reject === 'function' && this._promiseList.push({
            type: Chain.TYPES.REJECT,
            caller: reject
        })

        // 非等待状态执行
        if (this._status !== Chain.STATUS.PENDING) {
            this.resolve(this._result)
        }

		return this
    },
    
    /**
     * @description 添加失败回调
     * @param reject <Function> // 失败回调
     * @return <Chain>
    */
	catch: function (reject) {
        // 添加失败回调
        typeof reject === 'function' && this._promiseList.push({
            type: Chain.TYPES.REJECT,
            caller: reject
        })

        // 非等待状态执行
        if (this._status !== Chain.STATUS.PENDING) {
            this.resolve(this._result)
        }

		return this
    },
    
    /**
     * @description 执行回调
     * @param res <any> // 传入参数
    */
	resolve: function (res) {
        if (this._status === Chain.STATUS.FULFILLED) {
            return this.reject(res)
        }

        // 查找回调
        var prom = this._getPromise(Chain.TYPES.RESOLVE)
        if (!prom) {
            return undefined
        }

        // 改变状态
        this._status = Chain.STATUS.RESOLVED

        // 执行回调
        try {
            var result = prom.caller(res)
            if (result instanceof Chain) {
                result._merge(this)
            } else {
                this._result = result
                this.resolve(result)
            }
        }
        catch (e) {
            this.reject(e)
        }
    },
    
    /**
     * @description 执行失败回调
     * @param res <any> // 传入参数
     * @return <Chain>
    */
	reject: function (res) {
        // 改变状态
        this._status = Chain.STATUS.FULFILLED
        // 查找回调
        var prom = this._getPromise(Chain.TYPES.REJECT)
        if (!prom) {
            return undefined
        }

        // 执行回调
        try {
            var result = prom.caller(res)
            if (result instanceof Chain) {
                result._merge(this)
            } else {
                this._result = result
                this.reject(result)
            }
        }
        catch (e) {
            this.reject(e)
        }
    },
    
    /**
     * @description 获取回调对象
     * @param type <Chain.TYPES>
     * @return <Object>
    */
    _getPromise: function (type) {
        var prom = null, _promiseList = []
        // 无回调
        if (this._promiseList.length < 1) {
            return null
        }

        // 遍历查找
        this._promiseList.forEach(function (item) {
            // 重新组成回调组
            if (prom) {
                _promiseList.push(item)
            }

            // 匹配回调
            if (item.type === type && !prom) {
                prom = item
            }
        })

        // 重置回调组
        this._promiseList = _promiseList

        return prom
    },

    /**
     * @description 合并异步
    */
    _merge: function (chain) {
        // 合并回调组
        this._promiseList = this._promiseList.concat(chain._promiseList)
        // 初始状态主动执行
        if (this._status !== Chain.STATUS.PENDING) {
            this.resolve(this._result)
        }
    }
}

/**
 * @description 生成成功链
 * @return <Chain>
*/
Chain.resolve = function (data) {
    var chain = new Chain()
    chain._status = Chain.STATUS.RESOLVED
    chain._result = data
    return chain
}

/**
 * @description 生成错误链
 * @return <Chain>
*/
Chain.reject = function (data) {
    var chain = new Chain()
    chain._status = Chain.STATUS.FULFILLED
    chain._result = data
    return chain
}

// 状态表
Chain.STATUS = {
    PENDING: 'pending', // 等待
    RESOLVED: 'resolved', // 成功
    FULFILLED: 'fulfilled' // 错误
}

// 状态表
Chain.TYPES = {
    RESOLVE: 'resolve', // 成功
    REJECT: 'reject' // 错误
}